:- module(database_impl, [
	retrieve/1,
	retrieve/2,
	insert/1,
	insert/2,
	update/2,
	delete/1,
	delete/2,
	db_key/1,
	create_key/1,
	update_db/0,
	internal_data/1
			 ]).

:- include(db_impl).       % This file includes the definition of update_db/0.

:- use_package(assertions).
:- use_package(basicmodes).
:- use_package(regtypes).

%:- use_module(library(messages),[debug_message/2]).
:- use_module(search(utils),[log_message/1]).
:- use_module(library(prolog_sys),[statistics/2,new_atom/1]).
:- use_module(library(system),[datime/1]).
:- use_module(library(terms),[atom_concat/2]).
:- use_module(library(write),[writeq/2]).
%%:- use_module(engine(internals),[term_to_meta/2,module_concat/3]).

%% ==================================================================

:- pred database_backup(-Mode)

# "Determines if database updates backup is active or not. @var{Mode}
  can be @code{on} or @code{off}.".

%database_backup(on).
database_backup(off).

%% ==================================================================

:- regtype db_key(?Key)

# "@var{Key} is a (Prolog) representation of an unique indexing key,
  used by the database.  It is to be changed according the the
  database implementation, and it should not be changed or manipulated
  by the Prolog program.".

db_key(Key):- atm(Key).

:- regtype persistent_data(?Data)

# "@var{Data} is a valid structure to be stored on the database. In
  addition to the ontology-related structures, other internal and
  database-dependent structures are also allowed.".

persistent_data(Asset):- functor(Asset,asset,18).
persistent_data(Resource):- functor(Resource,resource,8).
persistent_data(User):- functor(User,user,2).
persistent_data(Organization):- functor(Organization,organization,5).
persistent_data(Certification):- functor(Certification,certification,9).
persistent_data(Ditem):- functor(Ditem,ditem,5).
persistent_data(Data):- internal_data(Data).

%% internal database structures.
internal_data(identificationtags(_,_,_)).
internal_data(requires(_,_,_)).
internal_data(synonyms(_,_)).
internal_data(generalizations(_,_)).
internal_data(translations(_,_,_)).
internal_data(authors(_,_)).
internal_data(maintainers(_,_)).
internal_data(descriptions(_,_)).
internal_data(uses(_,_,_)).
internal_data(cert_status(_,_)).

:- set_prolog_flag(multi_arity_warnings,off).

:- pred retrieve(?Key,?Pred): db_key * persistent_data

# "Retrieves from database the information requested. Given a database
  identifier @var{Key} or data pattern @var{Pred}, requests the
  corresponding key and data from de database.".

retrieve(Key,Pred):-
%	backup(retrieve(Key,Pred)),
	call(Pred),
	arg(1,Pred,Key).

:- pred retrieve(?Pred): internal_data

# "Retrieves database info for some internal db predicates.".
%:- multifile(sql_persistent_location/2).
retrieve(Pred):-
	internal_data(Pred),!,
%	backup(retrieve_internal(Pred)),
	call(Pred).

:- pred insert(in(Key),in(Pred)): db_key * persistent_data 

# "Inserts a new database item provided in @var{Pred}, with database
  identifier @var{Key}. Both @var{Pred} and @var{Key} must be ground
  terms.".

insert(Key,Pred):-
	arg(1,Pred,Key),
	backup(insert(Key,Pred)),
%	persdbrt_mysql_op:dbassertz_fact(Pred).
	persdbrt:assertz_fact(Pred).

:- pred create_key(-Key): db_key

# "Creates a new database key.".

create_key(Key):-
	new_atom(NewAtom),
	datime(X),
	X=datime(Y,M,D,H,Mn,S),
	DateN is ((((Y*13 + M)*32 + D)*24 + H)*60 + Mn)*60 + S,
	number_codes(DateN,DateS),
	atom_codes(Date,DateS),
	statistics(walltime,[_,MS]),
	number_codes(MS,MSs),
	atom_codes(MSa,MSs),
	atom_concat([NewAtom,Date,MSa],Key).
	

:- pred insert(?Pred): internal_data

# "Inserts database info for some internal db predicates.".

insert(Pred):-
	internal_data(Pred),
	backup(insert_internal(Pred)),
%	persdbrt_mysql_op:dbassertz_fact(Pred).
	persdbrt:assertz_fact(Pred).

:- pred update(in(Key),in(Pred)): db_key * persistent_data

# "Updates a database item with db identifier provided in @var{Key},
  with the data provided in @var{Pred}. If the data to be updated does
  not exist in the database yet, it is inserted.".

update(Key,Pred):-
	arg(1,Pred,Key),
	functor(Pred,F,A),
	functor(NewPred,F,A),
	arg(1,NewPred,Key),
	backup(update(Key,Pred)),
%	persdbrt_mysql_op:dbretract_fact(NewPred),
	( persdbrt:retract_fact(NewPred) -> true ; true),
%	persdbrt_mysql_op:dbassertz_fact(Pred).
	persdbrt:assertz_fact(Pred).
	
:- pred delete(+Key): db_key

# ".".

delete(Key,Pred):-
	arg(1,Pred,Key),
	backup(delete(Key,Pred)),
%	persdbrt_mysql_op:dbretract_fact(Pred).
	persdbrt:retract_fact(Pred).

:- pred delete(in(Pred)): internal_data

# "Deletes database info for some internal db predicates.".

delete(Pred):-
	internal_data(Pred),!,
	backup(delete_internal(Pred)),
%	persdbrt_mysql_op:dbretract_fact(Pred).
	persdbrt:retract_fact(Pred).

:- set_prolog_flag(multi_arity_warnings,on).

:- pred backup(in(Term)): term

# "Performs a backup copy of every database operation in a log file.".

backup(_Term):-
	database_backup(off), !.
backup(Term):-
	log_message(Term).

:- comment(version_maintenance,on).

:- comment(version(0*1+3,2003/07/16,17:10*00+'CEST'), "Added database
   tables for storing uses and cert_status lists for every resource.
   (Jesus Correas Fernandez)").

:- comment(version(0*1+2,2003/07/16,10:53*42+'CEST'), "added database
   implementation support for new definition field in ditem table.
   (Jesus Correas Fernandez)").

:- comment(version(0*1+1,2003/07/04,12:56*45+'CET'), "Changed
use_module and include references to use directory aliases.  (Jesus
Correas Fernandez)").
